package com.winit.resource.web;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.base.beans.LoginUser;
import com.winit.common.base.web.BaseController;
import com.winit.common.filter.UserInfoUtil;
import com.winit.common.util.ConfigUtil;
import com.winit.common.util.Constants;
import com.winit.common.util.MailUtil;
import com.winit.core.ci.vcs.SVN;
import com.winit.core.ci.vcs.exception.VCSException;
import com.winit.project.core.bean.PackageTypeEnum;
import com.winit.project.core.bean.ProjectInfo;
import com.winit.project.core.code.ProjectCode;
import com.winit.project.core.code.ProjectCodeConfig;
import com.winit.project.service.ProjectService;
import com.winit.project.util.ProjectUtil;
import com.winit.resource.beans.Config;
import com.winit.resource.manager.ConfigFileManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangjian on 16/7/22.
 * 配置文件管理
 */
@RestController
@RequestMapping("/config")
public class ConfigFileController extends BaseController {

    private static final Logger logger = LoggerFactory.getLogger(ConfigFileController.class);

    @Autowired
    private ConfigFileManager configFileManager;
    @Autowired
    private ProjectService projectService;

    /**
     * 配置文件管理,查询列表
     *
     * @param request
     * @return
     */
    @RequestMapping("/ConfigFileList")
    @ResponseBody
    public Map<String, Object> ConfigFileList(HttpServletRequest request) {
        LoginUser loginUser = UserInfoUtil.getUserInfo(request);
        if (loginUser == null) {
            logger.info("配置文件管理,查询列表,获取用户登录信息为空");
            return this.noUserRtn();
        }
        JSONObject jsonObject = new JSONObject();
        Map<String, Object> map = new HashMap<>();
        String selectProject = request.getParameter("selectProject");
        String selectFile = request.getParameter("selectFile");
        String selectEnv = request.getParameter("selectEnv");
        String filterConfig = request.getParameter("filterConfig");

        selectFile = selectFile.replace("$", "/");

        Config config = new Config();
        config.setSelectProject(selectProject);
        config.setSelectFile(selectFile.replace("/", "$"));
        config.setSelectEnv(selectEnv);
        config.setFilterConfig(Boolean.parseBoolean(filterConfig));
        config.setProjectList(new ArrayList<String>());
        config.setFileList(new ArrayList<JSONObject>());
        config.setEnvList(new ArrayList<String>());

        /**
         * 1.查询工程列表
         * 2.判断选择工程是否存在,不存在返回错误
         * 3.查询工程下配置文件列表
         * 4.查询可选环境列表
         * 5.判断所选配置文件是否存在,不存在返回错误
         * 6.判断所选环境是否存在,不存在返回错误
         */

        /**
         * step 1
         */
        List<ProjectInfo> projectInfoList = new ArrayList<>();
        try {
            projectInfoList = projectService.getProjectList("", PackageTypeEnum.ALL, false, false);
        } catch (Exception e) {
            logger.error("com.winit.resource.web.ConfigFileController.ConfigFileList 获取工程列表异常", e);
            map.put("code", "1");
            map.put("desc", "获取工程列表异常." + e.getMessage());
            return this.getRtnMap(map, loginUser, new JSONObject());
        }
        if (projectInfoList.size() == 0) {
            logger.info("配置文件管理,查询列表,工程列表为空");
            map.put("code", "1");
            map.put("desc", "工程列表为空");
            return this.getRtnMap(map, loginUser, new JSONObject());
        }
        //查询工程列表
        List<String> projectList = new ArrayList<>();
        for (ProjectInfo info : projectInfoList) {
            projectList.add(info.getProjectName());
        }

        if (StringUtils.isEmpty(selectProject)) {
            selectProject = projectList.get(0);
            config.setSelectProject(projectList.get(0));
        }
        config.setProjectList(projectList);

        /**
         * step 2
         */
        try {
            if (!StringUtils.isEmpty(selectProject)) {
                if (!projectService.isProjectExist(selectProject)) {
                    logger.info("配置文件管理,查询列表,工程不存在,selectProject=" + selectProject);
                    map.put("code", "1");
                    map.put("desc", "工程不存在");
                    jsonObject.put("config", config);
                    return this.getRtnMap(map, loginUser, jsonObject);
                }
            }
        } catch (Exception e) {
            logger.error("com.winit.resource.web.ConfigFileController.ConfigFileList 判断工程是否存在异常.selectProject=" + selectProject, e);
            map.put("code", "1");
            map.put("desc", "判断工程是否存在异常.projectName=" + selectProject + "." + e.getMessage());
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }

        /**
         * step 3
         */
        ProjectInfo projectInfo = null;
        try {
            projectInfo = projectService.getProjectInfo(config.getSelectProject());
        } catch (Exception e) {
            logger.error("com.winit.resource.web.ConfigFileController.ConfigFileList 获取工程信息异常.projectName=" + config.getSelectProject(), e);
            map.put("code", "1");
            map.put("desc", "获取工程信息异常.projectName=" + config.getSelectProject() + "." + e.getMessage());
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }
        String codePath = ProjectUtil.getProjectCodePath(config.getSelectProject());

        if (StringUtils.isEmpty(projectInfo.getVcsPath()) || StringUtils.isEmpty(codePath)) {
            logger.info("配置文件管理,查询工程信息,svn地址为空,selectProject=" + selectProject);
            map.put("code", "1");
            map.put("desc", "工程svn地址为空");
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }

        SVN svn = new SVN(projectInfo.getVcsPath(), codePath);

        ProjectCode projectCode = new ProjectCode(selectProject, codePath, svn);
        try {
            //工程代码不存在时,检出代码
            File codeFile = new File(codePath);
            if (!codeFile.exists()) {
                projectCode.checkOutProjectCode();
            }
        } catch (VCSException e) {
            e.printStackTrace();
            logger.error("配置文件管理,检出工程代码异常,selectProject=" + selectProject, e.getMessage());
            map.put("code", "1");
            map.put("desc", "检出工程代码异常," + e.getMessage());
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }

        ProjectCodeConfig projectCodeConfig = null;
        try {
            projectCodeConfig = new ProjectCodeConfig(config.getSelectProject(), codePath, svn, projectInfo.getConfigPath());
        } catch (Exception e) {
            logger.error("com.winit.resource.web.ConfigFileController.ConfigFileList 获取projectCodeConfig异常.projectName=" + config.getSelectProject(), e);
            map.put("code", "1");
            map.put("desc", "检出工程代码异常.projectName=" + config.getSelectProject() + "." + e.getMessage());
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }

        //查询工程配置文件列表
        List<String> fileList = configFileManager.getProjectConfigFileNameList(projectCodeConfig, config.isFilterConfig());
        if (fileList.size() == 0) {
            logger.info("配置文件管理,查询列表,配置文件列表为空");
            map.put("code", "1");
            map.put("desc", "配置文件列表为空");
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }
        if (StringUtils.isEmpty(selectFile) || !fileList.contains(selectFile)) {
            selectFile = fileList.get(0);
            config.setSelectFile(fileList.get(0).replace("/", "$"));
        }

        List<JSONObject> fList = new ArrayList<>();
        for (String s : fileList) {
            JSONObject json = new JSONObject();
            json.put("key", s);
            json.put("value", s.replace("/", "$"));
            fList.add(json);
        }

        config.setFileList(fList);

        /**
         * step 4
         */

        //查询环境列表
        List<String> envList = configFileManager.getEnvList(Constants.CONFIG_REPOSITORY);
        if (envList.size() == 0) {
            logger.info("配置文件管理,查询列表,环境列表为空");
            map.put("code", "1");
            map.put("desc", "环境列表为空");
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }
        if (StringUtils.isEmpty(selectEnv) || !envList.contains(selectEnv)) {
            selectEnv = envList.get(0);
            config.setSelectEnv(envList.get(0));
        }
        config.setEnvList(envList);


        /**
         * step 5
         */
        if (!StringUtils.isEmpty(selectFile)) {
            if (!projectCodeConfig.isConfigFileExist(selectFile)) {
                logger.info("配置文件管理,查询列表,工程配置文件不存在,selectProject=" + selectProject + ",selectFile=" + selectFile);
                map.put("code", "1");
                map.put("desc", "工程配置文件不存在");
                jsonObject.put("config", config);
                return this.getRtnMap(map, loginUser, jsonObject);
            }
        }

        /**
         * step 6
         */
        if (!StringUtils.isEmpty(selectEnv)) {
            if (!Constants.CONFIG_REPOSITORY.isEnvExist(selectEnv)) {
                logger.info("配置文件管理,查询列表,环境不存在,selectEnv=" + selectEnv);
                map.put("code", "1");
                map.put("desc", "环境不存在");
                jsonObject.put("config", config);
                return this.getRtnMap(map, loginUser, jsonObject);
            }

//            if(!configFileManager.isHasEnvPower(loginUser.getUserRole(),selectEnv)){
//                logger.info("配置文件管理,查询列表,环境无查看权限,selectEnv="+selectEnv+",userRole="+loginUser.getUserRole());
//                map.put("code","1");
//                map.put("desc","环境无查看权限");
//                jsonObject.put("config",config);
//                return this.getRtnMap(map,loginUser,jsonObject);
//            }

            if (!configFileManager.hasReadFilePower(loginUser, selectEnv, selectFile)) {
                logger.info("配置文件管理,查询列表,无文件查看权限,selectEnv=" + selectEnv + ",userRole=" + loginUser.getUserRole() + ",file=" + selectFile);
                map.put("code", "1");
                map.put("desc", "无文件查看权限");
                jsonObject.put("config", config);
                return this.getRtnMap(map, loginUser, jsonObject);
            }
        }

        try {
            JSONArray data = configFileManager.getConfigFiles(config);
            map.put("code", "0");
            jsonObject.put("config", config);
            jsonObject.put("configFiles", data);
            return this.getRtnMap(map, loginUser, jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", "1");
            map.put("desc", e.getMessage());
            jsonObject.put("config", config);
            return this.getRtnMap(map, loginUser, jsonObject);
        }
    }

    /**
     * 下载更新文件
     *
     * @param request
     * @return
     */
    @RequestMapping("/downLoadFile")
    @ResponseBody
    public Map<String, Object> downLoadFile(HttpServletRequest request) {
        LoginUser loginUser = UserInfoUtil.getUserInfo(request);
        if (loginUser == null) {
            logger.info("下载更新文件,获取用户登录信息为空");
            return this.noUserRtn();
        }
        String selectProject = request.getParameter("selectProject");
        String selectFile = request.getParameter("selectFile").replace("$", "/");
        String selectEnv = request.getParameter("selectEnv");
        Assert.hasText(selectProject, "下载更新文件,selectProject为空");
        Assert.hasText(selectFile, "下载更新文件,selectFile为空");
        Assert.hasText(selectEnv, "下载更新文件,selectEnv为空");

        Map<String, Object> map = null;
        try {
            map = configFileManager.updateFile(selectProject, selectFile, selectEnv);
        } catch (Exception e) {
            logger.error("com.winit.resource.web.ConfigFileController.downLoadFile 异常.selectProject=" + selectProject
                    + ",selectFile=" + selectFile + ",selectEnv=" + selectEnv, e);
            map.put("code", "1");
            map.put("desc", "更新配置文件异常." + e.getMessage());
        }

        return this.getRtnMap(map, loginUser, new JSONObject());
    }

    /**
     * 保存配置文件
     *
     * @param request
     * @return
     */
    @RequestMapping("/saveConfigFile")
    @ResponseBody
    public Map<String, Object> saveConfigFile(HttpServletRequest request) {
        LoginUser loginUser = UserInfoUtil.getUserInfo(request);
        if (loginUser == null) {
            logger.info("保存配置文件,获取用户登录信息为空");
            return this.noUserRtn();
        }

        String selectProject = request.getParameter("selectProject");
        String right = request.getParameter("right");
        String selectFile = request.getParameter("selectFile");
        String selectEnv = request.getParameter("selectEnv");
        Assert.hasText(selectProject, "保存配置文件,selectProject为空");
        Assert.hasText(right, "保存配置文件,right为空");
        Assert.hasText(selectFile, "保存配置文件,selectFile为空");
        Assert.hasText(selectEnv, "保存配置文件,selectEnv为空");
        JSONObject jsonObject = JSONObject.parseObject(right);

        logger.info("com.winit.resource.web.ConfigFileController.saveConfigFile selectProject=" + selectProject
                + ",selectEnv=" + selectEnv + ",selectFile=" + selectFile + ",user=" + loginUser.getAccount());

        Map<String, Object> map = new HashMap<>();

        try {
            //1、发送邮件通知
            if (selectEnv.startsWith("uc")) {
                String subject = "【重要】ucloud环境统一配置文件被修改";
                String body = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>Title</title></head><body>" +
                        "修改人：" + loginUser.getAccount() + "<br>修改工程：" + selectProject + "<br>修改文件：" + selectFile
                        + "<br>修改环境：" + selectEnv + "<br></body></html>";
                MailUtil.sendMail(ConfigUtil.getValue("update_config_notify_user"), subject, body);
            }

            //2、修改配置文件
            boolean flag = configFileManager.saveConfigFile(selectProject, jsonObject);
            if (flag) {
                map.put("code", "0");
                map.put("desc", "保存配置文件成功!");
            } else {
                map.put("code", "1");
                map.put("desc", "保存配置文件失败,请联系beetle管理员!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code", "1");
            map.put("desc", e.getMessage());
        }

        return this.getRtnMap(map, loginUser, new JSONObject());
    }

}
